package cn.javacc.tools;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.Transient;

import com.google.common.base.Charsets;
import com.google.common.io.Resources;

/**
 * @author Chi
 */
public class CodeBuilder {
    private Class<?> entityType;

    public CodeBuilder(Class<?> entityType) {
        super();
        this.entityType = entityType;
    }

    public String buildDao() {
        try {
            String content = Resources.toString(CodeBuilder.class.getResource("dao.tpl"), Charsets.UTF_8);
            TemplateBuilder template = new TemplateBuilder(content);
            template.set(getEntityContext());
            return template.build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public String buildDaoTest() {
        try {
            String content = Resources.toString(CodeBuilder.class.getResource("dao.test.tpl"), Charsets.UTF_8);
            TemplateBuilder template = new TemplateBuilder(content);
            template.set(getEntityContext());
            return template.build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public String buildService() {
        try {
            String content = Resources.toString(CodeBuilder.class.getResource("service.tpl"), Charsets.UTF_8);
            TemplateBuilder template = new TemplateBuilder(content);
            template.set(getEntityContext());
            return template.build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    public String buildController() {
        try {
            String content = Resources.toString(CodeBuilder.class.getResource("controller.tpl"), Charsets.UTF_8);
            TemplateBuilder template = new TemplateBuilder(content);
            template.set(getEntityContext());
            return template.build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    public String buildRestController() {
        try {
            String content = Resources.toString(CodeBuilder.class.getResource("restController.tpl"), Charsets.UTF_8);
            TemplateBuilder template = new TemplateBuilder(content);
            template.set(getEntityContext());
            return template.build();

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public String buildUpdateView() {
        try {
            String content = Resources.toString(CodeBuilder.class.getResource("view.update.tpl"), Charsets.UTF_8);
            TemplateBuilder template = new TemplateBuilder(content);
            template.set(getEntityContext());
            return template.build();

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public String buildDisplayView() {
        try {
            String content = Resources.toString(CodeBuilder.class.getResource("view.display.tpl"), Charsets.UTF_8);
            TemplateBuilder template = new TemplateBuilder(content);
            template.set(getEntityContext());
            return template.build();

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    public String buildListView() {
        try {
            String content = Resources.toString(CodeBuilder.class.getResource("view.list.tpl"), Charsets.UTF_8);
            TemplateBuilder template = new TemplateBuilder(content);
            template.set(getEntityContext());
            return template.build();

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    Map<String, Object> getEntityContext() {
        Map<String, Object> context = new HashMap<String, Object>();
        context.put("basePackage", this.getBasePackage());
        context.put("className", this.entityType.getName());
        context.put("simpleClassName", this.entityType.getSimpleName());
        context.put("entity", this.getEntityName());

        List<ObjectField> list = new ArrayList<ObjectField>();
        for (Field f : this.entityType.getDeclaredFields()) {
            if (Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers()) || f.isAnnotationPresent(Transient.class)) {
                continue;
            }

            ObjectField objectField = new ObjectField();
            objectField.setName(f.getName());
            objectField.setGetter("get" + Character.toUpperCase(f.getName().charAt(0)) + f.getName().substring(1, f.getName().length()));
            objectField.setSetter("set" + Character.toUpperCase(f.getName().charAt(0)) + f.getName().substring(1, f.getName().length()));

            if (f.getName().equals("id") || f.getName().equals("createTime") || f.getName().equals("lastUpdateTime") || f.getName().equals("status")) {
                objectField.setGenerated(true);
            }

            list.add(objectField);
        }
        context.put("fields", list);
        return context;
    }

    String getBasePackage() {
        StringBuilder b = new StringBuilder();

        int state = 0;

        for (int i = this.entityType.getName().length() - 1; i >= 0; i--) {
            char c = this.entityType.getName().charAt(i);
            if (c == '.') {
                state++;
                if (state == 2) {
                    b.append(this.entityType.getName().substring(0, i));
                    break;
                }
            }
        }

        return b.toString();
    }

    String getEntityName() {
        return Character.toLowerCase(this.entityType.getSimpleName().charAt(0)) + this.entityType.getSimpleName().substring(1, this.entityType.getSimpleName().length());
    }

    public class ObjectField {
        private String name;
        private String getter;
        private String setter;
        private boolean generated;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getGetter() {
            return getter;
        }

        public void setGetter(String getter) {
            this.getter = getter;
        }

        public String getSetter() {
            return setter;
        }

        public void setSetter(String setter) {
            this.setter = setter;
        }

        public boolean isGenerated() {
            return generated;
        }

        public void setGenerated(boolean generated) {
            this.generated = generated;
        }

    }
}
